home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / GDIDIB.PAK / FILEIO.C < prev    next >
C/C++ Source or Header  |  1997-05-06  |  13KB  |  432 lines

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1993 - 1995  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  MODULE:    fileio.c
  9. //
  10. //  PURPOSE:   Performs application and instance specific initialization.
  11. //
  12. //  FUNCTIONS:
  13. //    LoadDIBSection    - Loads a DIB from file into buffer created by
  14. //                        CreateDIBSection
  15. //    SaveDIB           - Saves the specified dib in a file
  16. //
  17. //  COMMENTS:
  18. //
  19.  
  20. #include <windows.h>       // required for all Windows applications
  21. #include <windowsx.h>
  22. #include <commctrl.h>      // prototypes and structure for the common controls.
  23.  
  24. #include "globals.h"       // prototypes specific to this application
  25. #include "resource.h"
  26. #include "toolbar.h"
  27. #include "palette.h"
  28. #include "dibutil.h"
  29.  
  30. // Dib Header Marker - used in writing DIBs to files
  31. #define DIB_HEADER_MARKER   ((WORD)('M' << 8) | 'B')
  32.  
  33. //
  34. //  FUNCTION: LoadDIBSection(HWND, LPSTR)
  35. //
  36. //  PURPOSE: Loads the specified DIB from a file, and reads it into the buffer
  37. //    created by CreateDIBSection.
  38. //
  39. //  PARAMETERS:
  40. //    hwnd          - specifies window for display context
  41. //    lpFileName    - specifies the file to load a DIB from
  42. //
  43. //  RETURN VALUE:
  44. //    A handle to a bitmap, or NULL if unsuccessful.
  45. //
  46. //  COMMENTS:
  47. //    The routines in this sample were not all written to handle OS/2 DIBs.
  48. //    This function will reject any file that is not a Windows DIB.
  49. //
  50. //
  51. HBITMAP LoadDIBSection(HWND hwnd, LPSTR lpFileName)
  52. {
  53.     HDC                 hdc;
  54.     HANDLE              hFile;
  55.     BITMAPFILEHEADER    bmfHeader;
  56.     UINT                nNumColors;
  57.     HDIB                hDIBNew;
  58.     LPBITMAPINFOHEADER  lpbih;
  59.     DWORD               dwBytesRead;
  60.  
  61.     // Set the cursor to a hourglass, in case the loading operation
  62.     // takes more than a sec, the user will know what's going on.
  63.     SetCursor(LoadCursor(NULL, IDC_WAIT));
  64.  
  65.     // open the DIB file
  66.     hFile = CreateFile(lpFileName,
  67.                        GENERIC_READ,
  68.                        FILE_SHARE_READ,
  69.                        NULL,
  70.                        OPEN_EXISTING,
  71.                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  72.                        NULL);
  73.  
  74.     if (hFile == INVALID_HANDLE_VALUE)
  75.     {
  76.         DIBError(ERR_FILENOTFOUND);
  77.         SetCursor(LoadCursor(NULL, IDC_ARROW));
  78.         return NULL;
  79.     }
  80.  
  81.     // read the BITMAPFILEHEADER from our file
  82.  
  83.     if (!ReadFile(hFile,
  84.                   &bmfHeader,
  85.                   sizeof(BITMAPFILEHEADER),
  86.                   &dwBytesRead,
  87.                   NULL)
  88.         || dwBytesRead != sizeof(BITMAPFILEHEADER))
  89.     {
  90.         DIBError(ERR_READ);
  91.         goto ErrExit;
  92.     }
  93.  
  94.     if (bmfHeader.bfType != 0x4d42)  // 'BM'
  95.     {
  96.         DIBError(ERR_NOT_DIB);
  97.         goto ErrExit;
  98.     }
  99.  
  100.     // Allocate memory for header & color table.
  101.     hDIBNew = GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
  102.  
  103.     if (!hDIBNew)
  104.     {
  105.         DIBError(ERR_MEMORY);
  106.         goto ErrExit;
  107.     }
  108.  
  109.     lpbih = (LPBITMAPINFOHEADER)GlobalLock(hDIBNew);
  110.     if (!lpbih)
  111.     {
  112.         DIBError(ERR_LOCK);
  113.         goto ErrExitFree;
  114.     }
  115.  
  116.     // read the BITMAPINFOHEADER
  117.     if (!ReadFile(hFile,
  118.                   lpbih,
  119.                   sizeof(BITMAPINFOHEADER),
  120.                   &dwBytesRead,
  121.                   NULL)
  122.         || dwBytesRead != sizeof(BITMAPINFOHEADER))
  123.     {
  124.         DIBError(ERR_READ);
  125.         goto ErrExitUnlock;
  126.     }
  127.  
  128.     // Check to see that it's a Windows DIB -- an OS/2 DIB would cause 
  129.     // problems with some of the functions in this sample since the fields
  130.     // in the header are different and color table entries are smaller.
  131.     // If it's not a Windows DIB (e.g. if biSize is wrong), return NULL.
  132.     if (lpbih->biSize != sizeof(BITMAPINFOHEADER))
  133.     {
  134.         DIBError(ERR_NOT_DIB);
  135.         goto ErrExitUnlock;
  136.     }
  137.  
  138.     // check to see if it's a format we support
  139.     switch (lpbih->biBitCount)
  140.     {
  141.         case 1:
  142.         case 4:
  143.         case 8:
  144.         case 16:
  145.         case 24:
  146.         case 32:
  147.  
  148.             // the format is supported so continue
  149.             break;
  150.  
  151.         default:
  152.             // the format isn't supported so fail
  153.             DIBError(ERR_UNSUPPORTEDFORMAT);
  154.             goto ErrExitUnlock;
  155.     }
  156.  
  157.     // Now determine the size of the color table and read it.  Since the
  158.     // bitmap bits are offset in the file by bfOffBits, do some special 
  159.     // processing to make sure the bits directly follow the color table  
  160.     if (!(nNumColors = (UINT)lpbih->biClrUsed))
  161.     {
  162.         // color table only for 8 bits per pixel or less
  163.  
  164.         if (lpbih->biBitCount <= 8)
  165.             nNumColors = 1 << lpbih->biBitCount; // standard size table
  166.     }
  167.  
  168.     // fill in some default values if they are zero
  169.     if (lpbih->biClrUsed == 0)
  170.         lpbih->biClrUsed = nNumColors;
  171.  
  172.     if (lpbih->biSizeImage == 0)
  173.         lpbih->biSizeImage = WIDTHBYTES(lpbih->biWidth * lpbih->biBitCount)
  174.                                 * lpbih->biHeight;
  175.  
  176.     if (nNumColors > 256)   // very rare, but possible
  177.     {
  178.         HDIB hDIBInfoTemp;
  179.  
  180.         // get a proper-sized buffer for header and color table
  181.         GlobalUnlock(hDIBNew);
  182.         hDIBInfoTemp = GlobalReAlloc(hDIBNew,
  183.                                      lpbih->biSize + nNumColors * sizeof(RGBQUAD),
  184.                                      0);
  185.  
  186.         if (!hDIBInfoTemp) // can't resize buffer for loading
  187.         {
  188.             DIBError(ERR_MEMORY);
  189.             goto ErrExitFree;
  190.         }
  191.         else
  192.             hDIBNew = hDIBInfoTemp;
  193.  
  194.         lpbih = (LPBITMAPINFOHEADER)GlobalLock(hDIBNew);
  195.         if (!lpbih)
  196.         {
  197.             DIBError(ERR_LOCK);
  198.             goto ErrExitFree;
  199.         }
  200.     }
  201.  
  202.     // read the color table
  203.     if (!ReadFile(hFile,
  204.                   (LPSTR)(lpbih) + lpbih->biSize,
  205.                   nNumColors * sizeof(RGBQUAD),
  206.                   &dwBytesRead,
  207.                   NULL)
  208.         || dwBytesRead != nNumColors * sizeof(RGBQUAD))
  209.     {
  210.         DIBError(ERR_READ);
  211.         goto ErrExitUnlock;
  212.     }
  213.  
  214.     // we've reached the point of no return (no undo)
  215.     // remove existing DIB section
  216.     RemoveDIBSection();
  217.  
  218.     // set global variable to new DIB header
  219.     hDIBInfo = hDIBNew;
  220.  
  221.     // create new DIB section
  222.     hdc = GetDC(hwnd);
  223.     hBitmap = CreateDIBSection(hdc,
  224.                                (LPBITMAPINFO)lpbih,
  225.                                DIB_RGB_COLORS,
  226.                                &lpvBits,
  227.                                0,
  228.                                0L);
  229.     ReleaseDC(hwnd, hdc);
  230.  
  231.     if (!hBitmap || !lpvBits)
  232.     {
  233.         DIBError(ERR_CREATEDIBSECTION);
  234.  
  235.         if (hBitmap)
  236.             DeleteObject(hBitmap);
  237.  
  238.         // create default wash for palette
  239.         if (bPalDevice)
  240.         {
  241.             HDC hdc;
  242.  
  243.             hdc = GetDC(hwnd);
  244.             hPalette = CreateHalftonePalette(hdc);
  245.             ReleaseDC(hwnd, hdc);
  246.         }
  247.  
  248.         goto ErrExitUnlock;
  249.     }
  250.  
  251.     // fill the buffer allocated by CreateDIBSection with bitmap bits        
  252.     SetFilePointer(hFile, bmfHeader.bfOffBits, NULL, FILE_BEGIN);
  253.     if (!ReadFile(hFile,
  254.                   lpvBits,
  255.                   lpbih->biSizeImage,
  256.                   &dwBytesRead,
  257.                   NULL)
  258.         || dwBytesRead != lpbih->biSizeImage)
  259.     {
  260.         // failed to read the DIB bits into the DIB section so get rid of it
  261.         DIBError(ERR_READ);
  262.         DeleteObject(hBitmap);
  263.         goto ErrExitUnlock;
  264.     }
  265.  
  266.     // create a palette for the DIB section from the DIB color table
  267.     hPalette = CreateDIBPalette(hDIBInfo);
  268.     // if hPalette is NULL it won't lead to failure condition, so don't check it
  269.  
  270.     // unlock the DIB header but don't free it!
  271.     GlobalUnlock(hDIBInfo);
  272.  
  273.     CloseHandle(hFile);
  274.     SetCursor(LoadCursor(NULL, IDC_ARROW));
  275.  
  276.     // update status of menu and toolbar
  277.     EnableMenuItem(hMenu, IDM_FILESAVEAS, MF_ENABLED);
  278.     EnableMenuItem(hMenu, IDM_FILECLOSE, MF_ENABLED);
  279.     EnableMenuItem(hMenu, IDM_CLEAR, MF_ENABLED);
  280.  
  281.     return hBitmap;
  282.  
  283. ErrExitUnlock:
  284.     // note: hDIBNew == hDIBInfo if failure occurred after CreateDIBSection call
  285.     GlobalUnlock(hDIBNew);
  286.  
  287. ErrExitFree:
  288.     // note: hDIBNew == hDIBInfo if failure occurred after CreateDIBSection call
  289.     GlobalFree(hDIBNew);
  290.  
  291. ErrExit:
  292.     CloseHandle(hFile);
  293.     SetCursor(LoadCursor(NULL, IDC_ARROW));
  294.     return NULL;
  295. }
  296.  
  297.  
  298. //
  299. //  FUNCTION: SaveDIB(HDIB, LPVOID, LPSTR)
  300. //
  301. //  PURPOSE:  Saves a DIB to a file.
  302. //
  303. //  PARAMETERS:
  304. //    hDib       - Handle to BITMAPFINFO and color table (if any) of dib
  305. //    lpvDIBBits - Pointer to bitmap bits
  306. //    lpFileName - Pointer to full pathname to save DIB under
  307. //
  308. //  RETURN VALUE:
  309. //    0 if successful, or one of ERR_INVALIDHANDLE, ERR_OPEN, ERR_LOCK or ERR_SAVE.
  310. //
  311. //  COMMENTS:
  312. //    The routines in this sample were not all written to handle OS/2 DIBs.
  313. //    This function will reject any file that is not a Windows DIB.
  314. //
  315. //
  316. #pragma argsused
  317. WORD SaveDIB(HDIB hDib, LPVOID lpvDIBits, LPSTR lpFileName)
  318. {
  319.      BITMAPFILEHEADER    bmfHdr;     // Header for Bitmap file
  320.      LPBITMAPINFOHEADER  lpbih;      // Pointer to DIB info structure
  321.      HANDLE              hFile;      // file handle for opened file
  322.      DWORD               dwDIBHeaderSize, dwDIBBitsSize, dwBytesWritten;
  323.      BOOL                bError;
  324.  
  325.     if (!hDib)
  326.         return ERR_INVALIDHANDLE;
  327.  
  328.     hFile = CreateFile(lpFileName,
  329.                        GENERIC_READ | GENERIC_WRITE,
  330.                        0,
  331.                        NULL,
  332.                        CREATE_ALWAYS,
  333.                        FILE_ATTRIBUTE_NORMAL,
  334.                        NULL);
  335.  
  336.     if (hFile == INVALID_HANDLE_VALUE)
  337.         return ERR_OPEN;
  338.  
  339.     // Get a pointer to the DIB memory, the first of which contains
  340.     // a BITMAPINFO structure
  341.  
  342.     lpbih = (LPBITMAPINFOHEADER)GlobalLock(hDib);
  343.     if (!lpbih)
  344.         return ERR_LOCK;
  345.  
  346.     // Check to see if we're dealing with an OS/2 DIB.  If so, don't
  347.      // save it because our functions aren't written to deal with these
  348.     // DIBs.
  349.  
  350.     if (lpbih->biSize != sizeof(BITMAPINFOHEADER))
  351.     {
  352.         GlobalUnlock(hDib);
  353.         return ERR_NOT_DIB;
  354.     }
  355.  
  356.     // Fill in the fields of the file header
  357.  
  358.     // Fill in file type (first 2 bytes must be "BM" for a bitmap)
  359.  
  360.     bmfHdr.bfType = DIB_HEADER_MARKER;  // "BM"
  361.  
  362.     // Calculating the size of the DIB is a bit tricky (if we want to
  363.     // do it right).  The easiest way to do this is to call GlobalSize()
  364.     // on our global handle, but since the size of our global memory may have
  365.     // been padded a few bytes, we may end up writing out a few too
  366.     // many bytes to the file (which may cause problems with some apps,
  367.     // like HC 3.0).
  368.     //
  369.     // So, instead let's calculate the size manually.
  370.     //
  371.      // We most likely do not have a packed DIB to work with, in other words,
  372.     // the bitmap bits do not immediately follow the DIB header and color table
  373.     // (if any).  So calculate sizes individually.
  374.  
  375.     // Calculate size of header and color table (if any)
  376.     dwDIBHeaderSize = lpbih->biSize + PaletteSize((LPSTR)lpbih);
  377.  
  378.     // Now calculate the size of the image
  379.  
  380.     // It's an RLE bitmap, we can't calculate size, so trust the biSizeImage
  381.     // field
  382.  
  383.      if ((lpbih->biCompression == BI_RLE8) || (lpbih->biCompression == BI_RLE4))
  384.         dwDIBBitsSize = lpbih->biSizeImage;
  385.     else
  386.     {
  387.         // It's not RLE, so size is Width (DWORD aligned) * Height
  388.  
  389.         dwDIBBitsSize = WIDTHBYTES(lpbih->biWidth * lpbih->biBitCount)
  390.                             * lpbih->biHeight;
  391.  
  392.         // Now, since we have calculated the correct size, why don't we
  393.         // fill in the biSizeImage field (this will fix any .BMP files which
  394.         // have this field incorrect).
  395.  
  396.         lpbih->biSizeImage = dwDIBBitsSize;
  397.     }
  398.  
  399.  
  400.     // Calculate file size by adding DIB size to sizeof(BITMAPFILEHEADER)
  401.  
  402.     bmfHdr.bfSize = dwDIBHeaderSize + dwDIBBitsSize + sizeof(BITMAPFILEHEADER);
  403.     bmfHdr.bfReserved1 = 0;
  404.     bmfHdr.bfReserved2 = 0;
  405.  
  406.     // Now, calculate the offset the actual bitmap bits will be in
  407.      // the file -- It's the Bitmap file header plus the DIB header,
  408.     // plus the size of the color table.
  409.  
  410.     bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + dwDIBHeaderSize;
  411.  
  412.     // Write the file header
  413.  
  414.     bError = (!WriteFile(hFile, &bmfHdr, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL)
  415.                 || dwBytesWritten != sizeof(BITMAPFILEHEADER));
  416.  
  417.     // Write the DIB header and the bits
  418.  
  419.      if (!bError)
  420.         bError = (!WriteFile(hFile, lpbih, dwDIBHeaderSize, &dwBytesWritten, NULL)
  421.                     || dwBytesWritten != dwDIBHeaderSize);
  422.  
  423.     if (!bError)
  424.         bError = (!WriteFile(hFile, lpvBits, dwDIBBitsSize, &dwBytesWritten, NULL)
  425.                     || dwBytesWritten != dwDIBBitsSize);
  426.  
  427.     GlobalUnlock(hDib);
  428.     CloseHandle(hFile);
  429.  
  430.      return (WORD)(bError ? ERR_SAVE : 0);
  431. }
  432.